﻿using System;
using System.Collections.Generic;
using CookComputing.XmlRpc;
//
using PerceptiveMCAPI.Types;
using PerceptiveMCAPI.Types.Internal;
//
namespace PerceptiveMCAPI.Methods
{

   public abstract class Api_BaseExecute
   {
      protected bool ValidationIsOK { get; set; }
      protected Api_BaseInput Input { get; private set; }
      private string apikey { get; set; }
      private string datacenter { get; set; }
      private string SubmitUrl { get; set; }

      // private new Api_BaseInput Input { get; set; }
      // private Api_BaseOutput Output { get; set; }
      #region ================================================================= Main
      // =============================================== constructors
      //public method() { }
      //// ---------
      //public method( methodInput input ) { Input = input; }
      //// =============================================== Execute
      //public methodOutput Execute()
      //{
      //   // empty constructor & Execute() is bad
      //   if ( Input == null )
      //      throw new ArgumentException( "Input class not provided" );
      //   // do the deed
      //   Output = Execute( Input );
      //   return Output;
      //}
      //// ----------------------------------
      // public methodOutput Execute( methodInput input )
      //{
      //   Input = input;
      //   Output = new methodOutput( Input );
      //   ValidationIsOK = true;
      //   //------------------------- validate it
      //   if ( Input.api_Validate )
      //   {
      //      Output.api_ValidatorMessages = ValidateInput.Validate( Input );
      //      ValidationIsOK = ValidateInput.IsOK( Output.api_ValidatorMessages );
      //   }
      //   //------------------------- do it
      //   if ( ValidationIsOK )
      //   {
      //      ApiRun( );  // execute API
      //   }
      //   // ---
      //   return Output;
      //}
      #endregion

      #region ================================================================= API Calls
      // // ---------------------------------------------------------- XmlRpc
      protected abstract void ExecuteXmlRpc();
      //{
      //   try
      //   {
      //      XmlRpcStruct rpcResult = apiXmlRpc.api.campaignClickStats( input.apikey, input.cid );
      //      Output.Format( rpcResult );
      //   }
      // catch ( XmlRpcFaultException fex )
      // {
      //    output.api_ErrorMessages.Add( apiException.FormatError( fex ) );
      // }
      // catch ( Exception ex )
      // {
      //    output.api_ErrorMessages.Add( apiException.FormatError( ex ) );
      // }

      //}
      // // ---------------------------------------------------------- Serial Post
      protected abstract void ExecuteSerialPost();
      //{
      //  try
      //  {
      //   Dictionary<string, string> dict = new Dictionary<string, string>();
      //   dict.Add( "apikey", input.apikey );
      //   dict.Add( "cid", input.cid );
      //   dict.Add( "start", input.start.ToString() );
      //   dict.Add( "limit", input.limit.ToString() );
      //   // -- do it
      //   string api_Request = "";
      //   string api_Response = apiSerial.ProcessRequest( Input, dict, out api_Request );
      //   Output.Format( api_Request, api_Response );
      // }
      // catch ( Exception ex )
      // {
      //    output.api_ErrorMessages.Add( apiException.FormatError( ex ) );
      // }
      //}
      #endregion

      #region ================================================================= virtuals

      // ----------------------------------------------- Run
      protected virtual void ApiRun( Api_BaseInput input, string apikey )
      {
         this.Input = input;
         this.apikey = apikey;
         //
         Input.SubmitUrl = FormatSubmitUrl();
         CheckForParmConflicts();
         // -----------------------------------------------------------
         EnumValues.AccessType accessType = Input.api_AccessType;
         switch ( accessType )
         {
            case EnumValues.AccessType.XmlRpc:
               CheckXmlRpcSettings();
               ExecuteXmlRpc();
               break;
            case EnumValues.AccessType.Serial:
               ExecuteSerialPost();
               break;
            default:
               throw new ArgumentException( "Invalid or missing parameter", "accessType" );
         }
      }

      // -------------------------------------------------------
      protected string FormatSubmitUrl()
      {
         string protocol = "http://";
         if ( Input.api_SecureAccess ) protocol = "https://";
         //
         if ( Input.api_DataCenter == "auto" ) datacenter = this.GetDataCenter( this.apikey );
         else datacenter = Input.api_DataCenter;
         //
         return string.Format( "{0}{1}.{2}", protocol, datacenter, MCAPISettings.api_URL );
      }

      // ----------------------------------------------------------------------------
      protected string GetDataCenter( string apikey )
      {
         string dc = "us1";   // default
         //---------------------------------------------
         // find the '-' and get the dc
         int dashix = apikey.LastIndexOf( "-" );
         if ( dashix > 0 )
         {
            dc = apikey.Substring( dashix + 1, 3 );
         }
         //
         return dc;
      }

      // ----------------------------------------------------------------------------
      protected void CheckXmlRpcSettings()
      {
         // check if settings for proxy need to be changed; if so, do it
         if ( apiXmlRpc.api.Timeout != Input.api_Timeout ||
              apiXmlRpc.api.Url != this.SubmitUrl )
         {
            apiXmlRpc.CreateProxy( datacenter, Input.api_SecureAccess, Input.api_Timeout );
         }
      }

      // ----------------------------------------------------------------------------
      protected void CheckForParmConflicts()
      {
         // access type to output type
         if ( ( Input.api_AccessType == EnumValues.AccessType.XmlRpc && Input.api_OutputType != EnumValues.OutputType.XmlRpc )
            || ( Input.api_AccessType == EnumValues.AccessType.Serial && Input.api_OutputType == EnumValues.OutputType.XmlRpc ) )
         {
            throw new ArgumentException(
               string.Format( "Access type to Output type mismatch: {0} -> {1}",
                  Input.api_AccessType.ToString(), Input.api_OutputType.ToString() )
                  );
         }
      }

      // ---------
      #endregion
   }
}